# -*- coding: utf-8 -*-
# @Time    : 2024/11/21 
# @Author  : bcbai
# @File    : diagnosticFunctions.py
# @Software: vscode
# @Description: 把诊断相关的函数封装 写在这里，方便 uds.py 调用， 也方便其他项目复用
# 和同星的库（libTSCANAPI）保持一致，返回： 0 表示成功， 1 表示失败

import time
from ctypes import *
from libTSCANAPI import tsdiag_can_session_control, tstp_can_request_and_get_response, tscan_get_error_description
from seedtokey import seedToKey_L5 
from myLog import logger



# UDS 22服务封装，返回数据处理后结果
# 根据响应数值的类型(Hex Array 、ASC等), 对结果进行不同处理，输出字符串
def uds22Service_response(udsHandle, request_data, response_value_type):
    response_data_size = c_int(100)  # 写100或1000都行
    response_data = (c_uint8 * 100)()
    try:
        r = tstp_can_request_and_get_response(udsHandle, request_data, len(request_data), response_data, response_data_size)
    except:
        str_read_result = "读取失败"
    if r != 0:
        res= c_char_p()
        tscan_get_error_description(r, res)
        logger.error("uds22Service_response error_Code:{}, desc:{}".format(r, res.value))
        str_read_result = '读取失败'
    else:
        list_read_result = [] 
        for i in range(response_data_size.value): 
            list_read_result.append(hex(response_data[i]))
        if list_read_result[0] != '0x62':
            str_read_result = " ".join([item[2:].zfill(2).upper() for item in list_read_result]) 
            str_read_result = '读取失败:' + str_read_result # 例如： 读取失败 7F 22 31
        else:
            list_read_result = list_read_result[3:]

            if response_value_type == 'Hex':
                # Hex Array转字符串
                str_read_result = " ".join([item[2:].zfill(2).upper() for item in list_read_result]) 
            if response_value_type == 'ASCii': 
                if '0xff' in list_read_result:  # 0xff不能通过asc转换，会报错，按照Hex处理
                    str_read_result = " ".join([item[2:].zfill(2).upper() for item in list_read_result]) 
                else:
                    # 16进制ASC转字符串，这里默认是Intel格式
                    str_read_result = ''.join([chr(int(item, 16)) for item in list_read_result]) 
            if response_value_type == 'Int8':
                # 16进制转Int字符串
                decimal_values  = [int(item, 16) for item in list_read_result]
                str_read_result = " ".join(map(str, decimal_values))
            if response_value_type == 'Int16':
                # 16进制转Int字符串
                # logger.info("list_read_result: {}".format(list_read_result))
                new_lst = []
                for i in range(0, len(list_read_result), 2):
                    first_value = list_read_result[i][2:]
                    # logger.info('first_value: {}'.format(first_value))
                    second_value = list_read_result[i + 1][2:]
                    # logger.info('second_value: {}'.format(second_value))
                    combined_value = f"0x{int(second_value, 16) * 256 + int(first_value, 16):x}"
                    new_lst.append(combined_value)
                # logger.info('new_lst: {}'.format(new_lst))
                decimal_values  = [int(item, 16) for item in new_lst]
                str_read_result = " ".join(map(str, decimal_values))
                # logger.info('decimal_strings: {}'.format(str_read_result )) 

    return str_read_result


# UDS 2E服务封装，返回数据处理后结果
def uds2EService_response(udsHandle, request_data):
    write_result = ''

    response_data_size = c_int(100)  # 写100或1000都行
    response_data = (c_uint8 * 100)()
    # 进10 03扩展会话
    r = tsdiag_can_session_control(udsHandle, 0x03)
    if r!= 0:
        res= c_char_p()
        tscan_get_error_description(r, res)
        logger.error("tsdiag_can_session_control error_Code:{}, desc:{}".format(r, res.value))
        write_result = '进扩展会话失败'
    else:
        # 安全访问
        security_level = 0x61
        security_access_result = uds27Service_response(udsHandle, security_level) 
        if  security_access_result != 0: 
            write_result = "安全访问失败"
        else:
            try:
                r = tstp_can_request_and_get_response(udsHandle, request_data, len(request_data), response_data, response_data_size)
            except:
                write_result = '失败'

            if r!= 0:
                res= c_char_p()
                tscan_get_error_description(r, res)
                logger.error("uds2EService_response error_Code:{}, desc:{}".format(r, res.value))
                write_result = '失败'
            else:
                list_result = [] 
                for i in range(response_data_size.value):
                    list_result.append(hex(response_data[i]))
                if list_result[0] != '0x6e': 
                    str_result = " ".join([item[2:].zfill(2).upper() for item in list_result]) 
                    write_result = '失败' + str_result
                else:
                    logger.info('成功 list_result: {}'.format(list_result))
                    write_result = 'OK'
    # 时间戳
    timestamp = time.time()
    # 将时间戳转换为 struct_time 对象
    time_struct = time.localtime(timestamp)
    hour = str(time_struct.tm_hour)
    minute = str(time_struct.tm_min)
    second = str(time_struct.tm_sec)
    return  write_result + " - " + hour + ":" + minute + ":" + second



# 27安全教校验 27 61 
def uds27Service_response(udsHandle, security_level):
    security_access_result = 0
    request_data = (c_uint8*2)(0x27, security_level)
    response_data_size = c_int(100)  # 写100或1000都行
    response_data = (c_uint8 * 100)()
    try:
        # 发送 27 61
        r = tstp_can_request_and_get_response(udsHandle, request_data, len(request_data), response_data, response_data_size)
    except:
        security_access_result = 1
    if r != 0:
        res= c_char_p()
        tscan_get_error_description(r, res)
        logger.error("uds22Service_response error_Code:{}, desc:{}".format(r, res.value))
        security_access_result = 1
    else:
        if response_data[0] == 127:  # 7F
            security_access_result = 1
        else:
            seed = []
            for i in range(2, response_data_size.value):     # 忽略前两个字节(67 61), 得到种子seed
                seed.append(hex(response_data[i]))
            seed = [int(elem[2:], 16) for elem in seed]      # seed列表里的元素 转成 int
            logger.info("---- seed: {}".format(seed))      # 例如：seed: [7, 195, 225, 240]
            key = []
            key = seedToKey_L5(seed)                         # seed 转 key 算法
            logger.info("---- key: {}".format(key))

            request_data = [0x27, security_level + 1] + key  # [27, 62, xx, xx, xx, xx]
            request_data_array = (c_uint8*len(request_data))(*request_data)  # 列表转c_uint数组
            # logger.info("request_data_array: {}".format(request_data_array))
            try:
                # 发送 27 62
                r = tstp_can_request_and_get_response(udsHandle, request_data_array, len(request_data_array), response_data, response_data_size)
            except:
                security_access_result = 1
            if r != 0:
                res= c_char_p()
                tscan_get_error_description(r, res)
                logger.error("uds22Service_response error_Code:{}, desc:{}".format(r, res.value))
                security_access_result = 1
            else:
                response_list = []
                for i in range(response_data_size.value):
                    response_list.append(hex(response_data[i]))
                if response_list[0] == '0x67':  # ['0x67', '0x62'] 表示安全校验成功
                    security_access_result = 0
                    logger.info("安全校验成功")
                else:
                    security_access_result = 1
                    logger.error("安全校验失败")

    return security_access_result



# 关闭DTC记录 85 02
def closeDTCRecord(udsHandle):
    result = 0
    request_data = (c_uint8*2)(0x85, 0x02)
    res = c_char_p()
    response_data_size = c_int(100)  # 写100或1000都行
    response_data = (c_uint8 * 100)()
    try:
        r = tstp_can_request_and_get_response(udsHandle, request_data, len(request_data), response_data, response_data_size)
    except:
        r = 1
    if r!= 0:
        tscan_get_error_description(r, res)
        logger.error("closeDTCRecord:  error_Code:{}, desc:{}".format(r, res.value))
        result = 1
    else:
        list_result = []
        for i in range(response_data_size.value):
            list_result.append(hex(response_data[i]))
        if list_result[0] == '0xc5' and list_result[1] == "0x2": #期望 c5 02
            result = 0  
        else:
            result = 1
    return result



# 开启DTC记录 85 81 00
def openDTCRecord(udsHandle):
    result = 0
    request_data = (c_uint8*3)(0x85, 0x81, 0x00)
    res = c_char_p()
    response_data_size = c_int(100)  # 写100或1000都行
    response_data = (c_uint8 * 100)()
    try:
        r = tstp_can_request_and_get_response(udsHandle, request_data, len(request_data), response_data, response_data_size)
    except:
        r = 1
    if r!= 0:
        tscan_get_error_description(r, res)
        logger.error("openDTCRecord:  error_Code:{}, desc:{}".format(r, res.value))
        result = 1
    else:
        result = 0  # 无需响应，不需要判断内容，只判断响应码
    return result




# 关闭NM和APP报文 28 01 03
def disableNMAndAppMessage(udsHandle):
    result = 0
    request_data = (c_uint8*3)(0x28, 0x01, 0x03)
    res = c_char_p()
    response_data_size = c_int(100)  # 写100或1000都行
    response_data = (c_uint8 * 100)()
    try:
        r = tstp_can_request_and_get_response(udsHandle, request_data, len(request_data), response_data, response_data_size)
    except:
        r = 1
    if r!= 0:
        tscan_get_error_description(r, res)
        logger.error("closeSomeMessage:  error_Code:{}, desc:{}".format(r, res.value))
        result = 1
    else:
        list_result = []
        for i in range(response_data_size.value):
            list_result.append(hex(response_data[i]))
        if list_result[0] == '0x68':           # 期望 68 01
            result = 0 
        else:
            result = 1
    return result



# 31服务的类型
type_preProgramConditionCheck = 0
type_checkDriverProgramIntegrity = 1
type_eraseMemory = 2
type_checkAppProgramIntegrity = 3
type_checkProgramDependency = 4

# 31 服务封装
def uds31Service_response(udsHandle, request_data, type_31service):
    result = 0
    res = c_char_p()
    response_data_size = c_int(100)  # 写100或1000都行
    response_data = (c_uint8 * 100)()
    try:
        r = tstp_can_request_and_get_response(udsHandle, request_data, len(request_data), response_data, response_data_size)
    except:
        r = 1
    if r!= 0:
        tscan_get_error_description(r, res)
        logger.error("uds31Service_response:  error_Code:{}, desc:{}".format(r, res.value))
        result = 1
    else:
        list_result = []
        for i in range(response_data_size.value):
            list_result.append(hex(response_data[i]))
        if type_31service == type_checkProgramDependency and list_result[-1] == '0x0':
            result = 1
        elif list_result[0] == '0x71':     # 期望 71 xx xx xx
            result = 0
        else:
            result = 1
    return result


# 11服务封装  复位ECU
def ECU_Reset(udsHandle, reset_time = 3):
    ECU_reset_result = 0
    request_ECU_Reset = (c_uint8*2)(0x11, 0x01)
    res = c_char_p()
    response_data_size = c_int(100)  # 写100或1000都行
    response_data = (c_uint8 * 100)()
    try:
        r = tstp_can_request_and_get_response(udsHandle, request_ECU_Reset, len(request_ECU_Reset), response_data, response_data_size)
    except:
        r = 1
    print("-------------  r:{}".format(r))
    if r!= 0:
        tscan_get_error_description(r, res)
        logger.error("ECU_Reset: error_Code:{}, desc:{}".format(r, res.value))
        ECU_reset_result = 1
    else:
        list_result = []
        for i in range(response_data_size.value):
            list_result.append(hex(response_data[i]))
        if list_result[0] == '0x51':
            ECU_reset_result = 0    # 期望51 01
            time.sleep(reset_time)  # 等待ECU重启， 等待时间可以根据实际情况调整
        else:
            ECU_reset_result = 1
    return ECU_reset_result


# 使能NM和APP报文 28 00 03
def enableNMAndAppMessage(udsHandle):
    result = 0
    request_data = (c_uint8*3)(0x28, 0x00, 0x03)
    res = c_char_p()
    response_data_size = c_int(100)  # 写100或1000都行
    response_data = (c_uint8 * 100)()
    try:
        r = tstp_can_request_and_get_response(udsHandle, request_data, len(request_data), response_data, response_data_size)
    except:
        r = 1
    if r!= 0:
        tscan_get_error_description(r, res)
        logger.error("closeSomeMessage:  error_Code:{}, desc:{}".format(r, res.value))
        result = 1
    else:
        list_result = []
        for i in range(response_data_size.value):
            list_result.append(hex(response_data[i]))
        if list_result[0] == '0x68':           # 期望 68 01
            result = 0 
        else:
            result = 1
    return result




